const url = require("url")
const compose = require("koa-compose")
const AppError = require("./app-error")

// 定义 uni-koa 应用类
function App() {
	this.middleware = []
	this.context = {}
}

// 注册中间件
App.prototype.use = function(fn) {
	this.middleware.push(fn)
	return this
}

// 创建上下文对象
App.prototype.createContext = function(event, context) {
	let ctx = {
		get status() { return this.__status },
		set status(val) { this.__status = val },
		get body() { return this.__body },
		set body(val) {
			this.__status = 200
			this.__body = val
		},
		get params() { return this.__params },
		set params(val) { this.__params = val },
		// 异常处理
		throw (code, msg, data) {
			// koa-parameter
			if (code === 422 && msg === "Validation Failed" && data) {
				msg = {
					message: msg,
					error: data.errors,
					params: data.params
				}
			}
			throw new AppError(code, msg)
		},
		// 响应头 koa-router 出错调用,弄个假的
		set() { return }
	}
	ctx = Object.assign(ctx, event, context, this.context)
	ctx.event = event
	ctx.context = context

	// get参数query中 头信息在 ctx.header 其他都在 ctx.request.body
	let path = event.action ? event.action : event.url
	let method = event.action ? "POST" : event.method

	let obj = url.parse(path, true)
	// 这里 action 请求都使用 post
	ctx.method = method ? method.toUpperCase() : "GET"

	ctx.url = path
	ctx.originalUrl = path //koa-jwt
	ctx.path = obj.pathname || "/"
	ctx.query = obj.query

	// token "Bearer "	
	ctx.header = {
		authorization: event.header && event.header.authorization || ""
	}
	ctx.request = { body: {} }
	ctx.state = {}

	// get 访问，data中数据在 query ,其他 在 ctx.request.body
	if (ctx.method === "GET") {
		ctx.query = Object.assign({}, ctx.query, event.data || {})
	} else {
		ctx.request.body = event.data || {}
	}

	return ctx
}

// 处理请求
App.prototype.handleRequest = async function(ctx) {
	ctx.status = 404 // 标识未找到	
	try {
		const fn = compose(this.middleware)
		await fn(ctx)
	} catch (err) {
		console.error(err)
		uniCloud.logger.error(err) // 打印到uniCloud的web控制台
		ctx.message = err.message
		ctx.status = err.name === "AppError" ? err.code : 500
	}

	// 设置新的 token,用于自动刷新token
	if (ctx.token && !ctx.body.token) {
		ctx.body.toke = ctx.token
	}

	// action 请求
	if (ctx.action && ctx.body) return ctx.body

	if (ctx.status === 404) ctx.message = `未找到 ${ctx.method} ${ctx.url} 请求方法`
	// 405：表示我有能力，但方法你没写。	
	if (ctx.status === 405) ctx.message = `不支持 ${ctx.method} ${ctx.url} 的请求方式`
	// 501：表示我没能力，完全看不懂你的请求。
	if (ctx.status === 501) ctx.message = `不支持 ${ctx.method} ${ctx.url} 当前请求所需要的功能`

	// 返回请求统一格式
	// 请求失败
	if (ctx.status !== 200) {
		return { code: ctx.status, msg: ctx.message || "" }
	}





	// 请求成功
	return { code: 0, data: ctx.body }
}

// 监听请求, 返回响应结果
App.prototype.listen = function() {
	return async (event, context) => {
		// 创建上下文
		let ctx = this.createContext(event, context)

		// 处理请求返回数据给客户端
		return await this.handleRequest(ctx)
	}
}

module.exports = App
